﻿using System;
using System.Runtime.Remoting.Activation;
using System.Runtime.Remoting.Contexts;
using System.Runtime.Remoting.Messaging;

namespace Sofire.AOP
{
    /// <summary>
    /// 一个 AOP 对象的特性。
    /// </summary>
    [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true)]
    public class AOPAttribute : ContextAttribute, IContributeEnvoySink, IContributeServerContextSink, IContributeObjectSink
    {
        private const string _AttributeName = "AOPAttribute";

        private BooleanValue _Enabled = BooleanValue.Default;
        /// <summary>
        /// 设置或获取一个值，指示 AOP 的启用状态。默认为 <see cref="System.BooleanValue.Default"/>，表示基于 <see cref="Sofire.AOP.AOPSetting.Enabled"/> 属性。
        /// </summary>
        public BooleanValue Enabled
        {
            get
            {
                return this._Enabled;
            }
            set
            {
                this._Enabled = value;
            }
        }

        private BooleanValue _RaiseOnEvent = BooleanValue.Default;
        /// <summary>
        /// 设置或获取一个值，指示 AOP 在事件触发过程中，是否再次或多次引发事件。默认为 <see cref="System.BooleanValue.Default"/>，表示基于 <see cref="Sofire.AOP.AOPSetting.RaiseOnEvent"/> 属性。
        /// </summary>
        public BooleanValue RaiseOnEvent
        {
            get
            {
                return this._RaiseOnEvent;
            }
            set
            {
                this._RaiseOnEvent = value;
            }
        }

        /// <summary>
        /// 获取一个值，指示 AOP 的启用状态。
        /// </summary>
        protected virtual bool IsEnabled
        {
            get
            {
                return this._Enabled == BooleanValue.True
                    || (this._Enabled == BooleanValue.Default && AOPSetting.Enabled);
            }
        }

        /// <summary>
        /// 获取一个值，指示 AOP 在事件触发过程中，是否再次或多次引发事件
        /// </summary>
        protected virtual bool IsRaiseOnEvent
        {
            get
            {
                return this._RaiseOnEvent == BooleanValue.True
                    || (this._RaiseOnEvent == BooleanValue.Default && AOPSetting.RaiseOnEvent);
            }
        }

        /// <summary>
        /// 初始化 <see cref="Sofire.AOP.AOPAttribute"/> 的新实例。
        /// </summary>
        public AOPAttribute() : base(_AttributeName) { }

        /// <summary>
        /// 将当前上下文属性添加到给定的消息。
        /// </summary>
        /// <param name="ctorMsg">将上下文属性添加到的 <see cref="System.Runtime.Remoting.Activation.IConstructionCallMessage"/>。</param>
        public override void GetPropertiesForNewContext(IConstructionCallMessage ctorMsg)
        {
            if(this.IsEnabled) base.GetPropertiesForNewContext(ctorMsg);
        }

        /// <summary>
        /// 返回一个指示上下文属性是否与新上下文兼容的布尔值。
        /// </summary>
        /// <param name="newCtx">已在其中创建属性的新上下文。</param>
        /// <returns>如果上下文属性与新上下文兼容，则为 true；否则为 false。</returns>
        public override bool IsNewContextOK(Context newCtx)
        {
            if(this.IsEnabled)
            {
                var newContextLogProperty = newCtx.GetProperty(_AttributeName);
                return newContextLogProperty != null && newContextLogProperty is AOPAttribute;
            }
            return false;
        }

        /// <summary>
        /// 返回一个指示该上下文参数是否满足上下文属性要求的布尔值。
        /// </summary>
        /// <param name="ctx">要在其中检查的上下文。</param>
        /// <param name="ctorMsg">将上下文属性添加到的 <see cref="System.Runtime.Remoting.Activation.IConstructionCallMessage"/>。</param>
        /// <returns>如果传入的上下文一切正常，则为 true；否则为 false。</returns>
        public override bool IsContextOK(Context ctx, IConstructionCallMessage ctorMsg)
        {
            return !this.IsEnabled;
            //return false;
        }

        #region IContributeServerContextSink 成员

        // 构造函数只在此函数触发
        IMessageSink IContributeServerContextSink.GetServerContextSink(IMessageSink nextSink)
        {
            if(this.IsEnabled) return new ConstructionCallSink(nextSink);
            return nextSink;
        }

        #endregion

        #region IContributeEnvoySink 成员

        // 在事件内设置有触发
        IMessageSink IContributeEnvoySink.GetEnvoySink(MarshalByRefObject obj, IMessageSink nextSink)
        {
            if(this.IsEnabled && this.IsRaiseOnEvent) return new MethodCallSink(obj, nextSink);

            return nextSink;
        }

        #endregion

        #region IContributeObjectSink 成员

        // 在事件内设置无触发
        IMessageSink IContributeObjectSink.GetObjectSink(MarshalByRefObject obj, IMessageSink nextSink)
        {
            if(this.IsEnabled && !this.IsRaiseOnEvent) return new MethodCallSink(obj, nextSink);
            return nextSink;
        }

        #endregion

    }
}
